package com.share.infrastructure.persistent.repository;

import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy;
import com.alibaba.fastjson.JSON;
import com.share.domain.award.model.aggregate.GiveOutPrizeAggregate;
import com.share.domain.award.model.aggregate.UserAwardRecordAggregate;
import com.share.domain.award.model.entity.TaskEntity;
import com.share.domain.award.model.entity.UserAwardRecordEntity;
import com.share.domain.award.model.entity.UserCreditAwardEntity;
import com.share.domain.award.model.valobj.AccountStateVO;
import com.share.domain.award.repository.IAwardRepository;
import com.share.infrastructure.event.EventPublisher;
import com.share.infrastructure.persistent.dao.*;
import com.share.infrastructure.persistent.po.Task;
import com.share.infrastructure.persistent.po.UserAwardRecord;
import com.share.infrastructure.persistent.po.UserCreditAccount;
import com.share.infrastructure.persistent.po.UserRaffleOrder;
import com.share.types.enums.ResponseCode;
import com.share.types.exception.AppException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;

@Repository
@Slf4j
public class AwardRepository implements IAwardRepository {
    @Resource
    private IUserAwardRecordDao userAwardRecordDao;
    @Resource
    private ITaskDao taskDao;

    @Resource
    private IAwardDao awardDao;

    @Resource
    private IUserRaffleOrderDao userRaffleOrderDao;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private EventPublisher eventPublisher;
    @Resource
    private IDBRouterStrategy dbRouter;

    @Resource
    private IUserCreditAccountDao userCreditAccountDao;

    /**
     * 写入用户奖品记录
     * @param userAwardRecordAggregate
     */
    @Override
    public void saveUserAwardRecord(UserAwardRecordAggregate userAwardRecordAggregate) {
        UserAwardRecordEntity userAwardRecordEntity = userAwardRecordAggregate.getUserAwardRecordEntity();
        TaskEntity taskEntity = userAwardRecordAggregate.getTaskEntity();
        String userId = userAwardRecordEntity.getUserId();
        Long activityId = userAwardRecordEntity.getActivityId();
        Integer awardId = userAwardRecordEntity.getAwardId();


        UserAwardRecord userAwardRecord = new UserAwardRecord();
        userAwardRecord.setUserId(userId);
        userAwardRecord.setAwardState(userAwardRecordEntity.getAwardState().getCode());
        userAwardRecord.setAwardId(awardId);
        userAwardRecord.setAwardTitle(userAwardRecordEntity.getAwardTitle());
        userAwardRecord.setActivityId(activityId);
        userAwardRecord.setOrderId(userAwardRecordEntity.getOrderId());
        userAwardRecord.setStrategyId(userAwardRecordEntity.getStrategyId());
        userAwardRecord.setAwardTime(userAwardRecordEntity.getAwardTime());

        Task task = new Task();
        task.setUserId(taskEntity.getUserId());
        task.setTopic(taskEntity.getTopic());
        task.setMessageId(taskEntity.getMessageId());
        task.setMessage(JSON.toJSONString(taskEntity.getMessage()));
        task.setState(taskEntity.getState().getCode());


        UserRaffleOrder userRaffleOrderReq = new UserRaffleOrder();
        userRaffleOrderReq.setUserId(userAwardRecordEntity.getUserId());
        userRaffleOrderReq.setActivityId(userAwardRecordEntity.getActivityId());
        userRaffleOrderReq.setOrderId(userAwardRecordEntity.getOrderId());


        try{
            dbRouter.doRouter(userId);
            transactionTemplate.execute(state->{
                try {
                    //写入记录
                    userAwardRecordDao.insert(userAwardRecord);
                    //写入任务,避免mq消息推送失败:兜底-定时任务扫描task表进行补发
                    taskDao.insert(task);

                    //更新抽奖单

                    int count = userRaffleOrderDao.updateUserRaffleOrderStateUsed(userRaffleOrderReq);
                    if(1!=count){
                        state.setRollbackOnly();
                        log.error("写入中奖记录,抽奖单已被使用:userId:{},activityId:{},awardId:{}",userId,activityId,awardId);
                        throw new AppException(ResponseCode.ACTIVITY_USER_RAFFLE_ORDER_BEUSER_ERROR.getCode(),ResponseCode.ACTIVITY_USER_RAFFLE_ORDER_BEUSER_ERROR.getInfo());
                    }

                    return 1;
                }catch (DuplicateKeyException e){
                    state.setRollbackOnly();
                    log.error("写入中奖记录,唯一索引冲突:userId:{},activityId:{},awardId:{}",userId,activityId,awardId,e);
                    throw new AppException(ResponseCode.INDEX_DUP.getCode(),ResponseCode.INDEX_DUP.getInfo());
                }
            });
        }finally {
            dbRouter.clear();
        }

        //发送mq消息
        try {
            eventPublisher.publish(task.getTopic(),task.getMessage());
            taskDao.updateTaskSendMessageCompleted(task);
        }catch (Exception e){
            log.error("写入中奖记录,发送MQ消息失败userId:{},topic:{}",userId,task.getTopic());
            taskDao.updateTaskSendMessageFail(task);
        }
    }

    @Override
    public String queryAwardConfig(Integer awardId) {
        return awardDao.queryAwardConfigByAwardId(awardId);
    }

    @Override
    public void saveGiveOutPrizesAggregate(GiveOutPrizeAggregate giveOutPrizeAggregate) {
        String userId = giveOutPrizeAggregate.getUserId();
        UserAwardRecordEntity userAwardRecordEntity = giveOutPrizeAggregate.getUserAwardRecordEntity();
        UserCreditAwardEntity userCreditAwardEntity = giveOutPrizeAggregate.getUserCreditAwardEntity();

        //更新发奖记录
        UserAwardRecord userAwardRecordReq = new UserAwardRecord();
        userAwardRecordReq.setUserId(userId);
        userAwardRecordReq.setOrderId(userAwardRecordEntity.getOrderId());
        userAwardRecordReq.setAwardState(userAwardRecordEntity.getAwardState().getCode());

        UserCreditAccount userCreditAccountReq = new UserCreditAccount();
        userCreditAccountReq.setUserId(userId);
        userCreditAccountReq.setTotalAmount(userCreditAwardEntity.getCreditAmount());
        userCreditAccountReq.setAvailableAmount(userCreditAwardEntity.getCreditAmount());
        userCreditAccountReq.setAccountStatus(AccountStateVO.open.getCode());

        try{
            dbRouter.doRouter(userId);
            transactionTemplate.execute(state->{
                try {
                    int i = userCreditAccountDao.updateAddAmount(userCreditAccountReq);
                    if(0==i){
                        userCreditAccountDao.insert(userCreditAccountReq);
                    }
                    int j = userAwardRecordDao.updateAwardRecordCompleteState(userAwardRecordReq);
                    if(0==j){
                        log.error("更新奖品记录，拦截重复操作:userId:{},giveOutPrizeAggregate:{}",userId,JSON.toJSONString(giveOutPrizeAggregate));
                        state.setRollbackOnly();
                    }
                    return 1;
                }catch (DuplicateKeyException e){
                    state.setRollbackOnly();
                    log.error("更新中奖记录，唯一索引冲突:userId:{}",userId);
                    throw new AppException(ResponseCode.INDEX_DUP.getCode(),ResponseCode.INDEX_DUP.getInfo());
                }
            });
        }finally {
            dbRouter.clear();
        }

    }

    @Override
    public String queryAwardKey(Integer awardId) {
        return awardDao.queryAwardKeyByAwardId(awardId);
    }
}
